<script setup>
  import { ref, watch, reactive, computed, onMounted, toRaw } from 'vue'
  import { useForm } from 'vee-validate'
  import {
    buildYupSchema,
    getFieldData,
    getDefaults,
    getSubmitErrorCallback,
    getSubmitModelCallback,
  } from '@/helpers/form'
  import { useCustomerStore } from '@/stores/customer'
  import { useProjectStore } from '@/stores/project'
  import { useTaskConfigStore } from '@/stores/task'
  import Select2 from '@/components/forms/Select2.vue'
  import Input from '@/components/forms/Input.vue'
  import Icon from '@/components/Icon.vue'
  import FormModalLayout from '@/layouts/FormModalLayout.vue'
  import CustomerFormComponent from '@/components/customer/CustomerFormComponent.vue'
  import ProjectFormComponent from '@/components/project/ProjectFormComponent.vue'
  import { useTaskStore } from '@/stores/task'

  const props = defineProps({
    initialData: Object,
  })
  const emit = defineEmits(['saved', 'cancel', 'error'])

  // La création se fait depuis un projet (ou depuis un client)
  const isFromProject = !!props.initialData.project_id

  // Chargement de la configuration de la page
  const formConfigStore = useTaskConfigStore()
  // Urls utilisées pour
  //  - le chargement des clients
  //  - le lancement du formulaire d'ajout de client à la volée
  const customerUrl = formConfigStore.getOptions('customers_url')
  const customerConfigUrl = formConfigStore.getOptions('customers_config_url')
  const projectUrl = formConfigStore.getOptions('projects_url')
  const projectConfigUrl = formConfigStore.getOptions('projects_config_url')

  // Chargement des options des selects
  const customerStore = useCustomerStore()
  const projectStore = useProjectStore()
  const taskStore = useTaskStore()

  async function loadProjectOptions() {
    return await projectStore.loadProjects(props.initialData.company_id, {
      fields: ['id', 'name'],
      related: ['customer_ids', 'phases', 'business_types'],
    })
  }
  async function loadCustomerOptions() {
    return await customerStore.loadCustomers(props.initialData.company_id, {
      fields: ['id', 'label'],
      related: ['project_ids'],
    })
  }
  let customersCollection = ref([])
  let projectsCollection = ref([])
  onMounted(async () => {
    customersCollection.value = await loadCustomerOptions()
    projectsCollection.value = await loadProjectOptions()
  })

  // Configuration du schéma de formulaire et du Form vee-validate
  const jsonSchema = formConfigStore.getSchema('default')
  const formSchema = buildYupSchema(jsonSchema)
  const initialValues = getDefaults(formSchema)
  const { values, handleSubmit, setFieldValue, isSubmitting } = useForm({
    validationSchema: formSchema,
    initialValues: initialValues,
  })
  // **** Update des selects
  // update les options en fonction du projet ou du client sélectionné
  // helpers renvoyant les options
  /**
   * Fonction filtrant les dossiers à proposer
   */
  const projects = () => {
    // Getting the raw list in place of the ref's proxy value
    const _projects = toRaw(projectsCollection.value)
    let result
    if (isFromProject) {
      result = _projects
    } else {
      const customer_id = parseInt(values.customer_id)
      if (!customer_id) {
        result = []
      } else if (newCustomerId === customer_id) {
        // On vient d'ajouter ce client, on propose tous les projets.
        result = _projects
      } else {
        const customerProjects = _projects.filter((project) => {
          return project.customer_ids.includes(customer_id)
        })

        if (customerProjects.length === 0) {
          result = _projects
        } else {
          const otherProjects = _projects.filter((project) => {
            return !project.customer_ids.includes(customer_id)
          })
          result = [{ text: 'Dossiers du client', children: customerProjects }]
          if (otherProjects.length > 0) {
            result.push({ text: 'Autres dossiers', children: otherProjects })
          }
        }
      }
    }
    return result
  }
  /**
   * Fonction filtrant les clients à proposer
   */
  const customers = () => {
    console.log('computing customers')
    const _customers = toRaw(customersCollection.value)
    let result
    if (!isFromProject) {
      result = _customers
    } else {
      const project_id = parseInt(values.project_id)
      if (project_id) {
        const projectCustomers = _customers.filter((customer) => {
          return customer.project_ids.includes(project_id)
        })
        if (projectCustomers.length === 0) {
          result = _customers
        } else {
          const otherCustomers = _customers.filter((customer) => {
            return !customer.project_ids.includes(project_id)
          })
          result = [{ text: 'Clients du projet', children: projectCustomers }]
          if (otherCustomers.length > 0) {
            result.push({ text: 'Autres clients', children: otherCustomers })
          }
        }
      } else {
        result = []
      }
    }
    return result
  }
  /**
   * Fonction filtrant les sous-dossiers à proposer
   */
  const phases = () => {
    console.log('computing phases')
    let result = []
    if (values.project_id) {
      const project = projectStore.getByid(values.project_id)
      if (project) {
        result = project.phases
      }
    }
    return result
  }
  /**
   * Fonction filtrant les types d'affaire à proposer
   */
  const businessTypes = () => {
    console.log('computing business types')
    let result = []
    if (values.project_id) {
      const project = projectStore.getByid(values.project_id)
      if (project) {
        result = project.business_types
      }
    }
    return result
  }
  // Computed pour que les select s'updatent automatiquement
  let phaseOptions = computed(() => phases())
  let businessTypeOptions = computed(() => businessTypes())
  let customerOptions = computed(() => customers())
  let projectOptions = computed(() => projects())

  // Ref permettant de checker si l'on a juste ajouté un client
  //(dans ce cas on liste tous les projets)
  let newCustomerId = null
  // Ref permettant de marquer que l'on va associer un projet à un client
  // lors de la validation
  let clientAlreadyInProject = ref(true)

  /**
   *  Watcher pour updater les références quand le dossier change
   */
  watch(
    () => values.project_id,
    (newValue, prevValue) => {
      console.log(`project_id changed from ${prevValue} to ${newValue}`)
      if (!newValue) {
        return
      }
      const project = projectStore.getByid(newValue)
      // Client
      if (isFromProject) {
        if (project.customer_ids && project.customer_ids.length == 1) {
          setFieldValue('customer_id', project.customer_ids[0])
        }
      }
      // Sous-dossier
      if (project.phases && project.phases.length == 1) {
        setFieldValue('phase_id', project.phases[0].id)
      }
      // Type d'affaire
      if (project.default_business_type_id) {
        setFieldValue('business_type_id', project.default_business_type_id)
      } else if (project.business_types && project.business_types.length == 1) {
        setFieldValue('business_type_id', project.business_types[0].id)
      }
    }
  )
  /**
   * Watcher pour updater les références quand le client change
   */
  watch(
    () => values.customer_id,
    (newValue, prevValue) => {
      console.log(`customer_id changed from ${prevValue} to ${newValue}`)
      if (!newValue) {
        return
      }
      const customer = customerStore.getByid(newValue)
      if (!isFromProject) {
        if (customer.project_ids && customer.project_ids.length == 1) {
          clientAlreadyInProject.value = true
          setFieldValue('project_id', customer.project_ids[0])
        } else if (customer.project_ids.length === 0) {
          clientAlreadyInProject.value = false
          values.project_id = null
        } else {
          clientAlreadyInProject.value = true
          values.project_id = null
        }
      }
    }
  )
  /**
   * Fonction permettant d'ajouter un client à un dossier existant
   */
  async function addCustomerToProject(project, customerId) {
    if (customerId) {
      projectStore.setCurrentProjectId(project.id)
      let customerIds = [customerId]
      if (project.customer_ids) {
        customerIds = customerIds.concat(project.customer_ids)
      }
      const payload = {
        id: project.id,
        customers: customerIds,
      }
      return await projectStore.saveProject(payload)
    }
  }

  // Affichage des popups pour la création de projet / client
  const showCustomerForm = ref(false)
  const showProjectForm = ref(false)
  const onCustomerAddClick = () => {
    showCustomerForm.value = true
  }
  const onHideCustomerForm = () => {
    showCustomerForm.value = false
  }
  const onProjectAddClick = () => {
    showProjectForm.value = true
  }
  const onHideProjectForm = () => {
    showProjectForm.value = false
  }

  /**
   * Callback après la création d'un nouveau client
   */
  const onCustomerSaved = async (customer) => {
    newCustomerId = customer.id
    if (isFromProject) {
      const project_id = values.project_id
      if (project_id) {
        // On ajoute le client au projet déjà sélectionné
        const selectedProject = projectStore.getByid(project_id)
        await addCustomerToProject(selectedProject, customer.id)
      }
    } else {
      delete values.project_id
    }
    showCustomerForm.value = false
    customersCollection.value = await loadCustomerOptions()
    customerOptions.value = customers()
    // Hack pour ajouter le customer id dans le validateur du schéma de formulaire
    formSchema.fields.customer_id._whitelist.add(customer.id)
    setFieldValue('customer_id', customer.id)
  }

  /**
   * Callback après la création de un nouveau dossier
   */
  const onProjectSaved = async (project) => {
    if (!isFromProject) {
      const customerId = values.customer_id
      if (customerId) {
        // On ajoute le client déjà sélectionné au nouveau projet
        await addCustomerToProject(project, customerId)
        newCustomerId = null
      }
    } else {
      delete values.customer_id
    }
    showProjectForm.value = false
    projectsCollection.value = await loadProjectOptions()
    // Hack pour ajouter le project id dans le validateur du schéma de formulaire
    formSchema.fields.project_id._whitelist.add(project.id)
    setFieldValue('project_id', project.id)
  }

  // Props utilisées pour générer les champs
  // On utilise des variables intermédiaire pour
  // les mettre dans le bon ordre (dossier en premier ou client en premier)
  // ce que l'on ne peut pas faire dans le template
  const customerFieldProps = reactive({
    fieldName: 'customer_id',
    labelKey: 'label',
    options: customerOptions,
    onAdd: onCustomerAddClick,
    title: 'Ajouter un client',
  })
  const projectFieldProps = reactive({
    fieldName: 'project_id',
    labelKey: 'name',
    options: projectOptions,
    onAdd: onProjectAddClick,
    title: 'Ajouter un dossier',
  })

  let firstFieldProps, secondFieldProps
  if (isFromProject) {
    // Projet en premier
    ;[secondFieldProps, firstFieldProps] = [
      customerFieldProps,
      projectFieldProps,
    ]
  } else {
    // Client en premier
    ;[firstFieldProps, secondFieldProps] = [
      customerFieldProps,
      projectFieldProps,
    ]
  }

  /**
   * Fonction lancée lorsque la validation des données par vee-validate
   * est réussie/en erreur
   */
  const onSubmitSuccess = getSubmitModelCallback(emit, taskStore.createTask)
  const onSubmitError = getSubmitErrorCallback(emit)

  const onSubmit = handleSubmit(onSubmitSuccess, onSubmitError)
  const getData = (fieldName) => getFieldData(formSchema, fieldName)
</script>
<template>
  <div>
    <form @submit="onSubmit">
      <fieldset class="deformFormFieldset">
        <Input v-bind="getData('name')" />

        <div class="layout flex end_button">
          <div class="col-content">
            <Select2
              v-bind="getData(firstFieldProps.fieldName)"
              :name="firstFieldProps.fieldName"
              idKey="id"
              :labelKey="firstFieldProps.labelKey"
              :options="firstFieldProps.options"
              :modelValue="values[firstFieldProps.fieldName]"
            />
          </div>
          <div class="col-button">
            <button
              type="button"
              class="btn icon only"
              @click="firstFieldProps.onAdd"
              :title="firstFieldProps.title"
              :aria-label="firstFieldProps.title"
            >
              <Icon name="plus" />
            </button>
          </div>
        </div>
        <div class="form-group layout flex end_button">
          <div class="col-content">
            <Select2
              v-bind="getData(secondFieldProps.fieldName)"
              :name="secondFieldProps.fieldName"
              idKey="id"
              :labelKey="secondFieldProps.labelKey"
              :options="secondFieldProps.options"
              :modelValue="values[secondFieldProps.fieldName]"
              :description="
                clientAlreadyInProject
                  ? null
                  : 'Le client sera automatiquement associé à ce nouveau projet'
              "
            />
          </div>
          <div class="col-button">
            <button
              type="button"
              class="btn icon only"
              @click="secondFieldProps.onAdd"
              :title="secondFieldProps.title"
              :aria-label="secondFieldProps.title"
            >
              <Icon name="plus" />
            </button>
          </div>
        </div>
        <Input
          v-if="phaseOptions.length == 1"
          type="hidden"
          v-bind="getData('business_type_id')"
        />
        <Select2
          v-if="phaseOptions.length > 1"
          v-bind="getData('phase_id')"
          name="phase_id"
          idKey="id"
          labelKey="name"
          :options="phaseOptions"
          :modelValue="values['phase_id']"
        />
        <Input
          v-if="businessTypeOptions.length == 1"
          type="hidden"
          v-bind="getData('business_type_id')"
        />
        <Select2
          v-if="businessTypeOptions.length > 1"
          v-bind="getData('business_type_id')"
          name="business_type_id"
          idKey="id"
          labelKey="label"
          :options="businessTypeOptions"
          :modelValue="values['business_type_id']"
        />
      </fieldset>
      <div class="btn-group">
        <button
          id="deformsubmit"
          name="submit"
          type="submit"
          class="btn btn-primary btn btn-primary"
          value="submit"
          :disabled="isSubmitting"
        >
          Valider
        </button>
        <button
          id="deformcancel"
          name="cancel"
          type="button"
          class="btn btn-default"
          @click="() => emit('cancel')"
        >
          Annuler
        </button>
      </div>
    </form>
    <CustomerFormComponent
      v-if="showCustomerForm"
      :edit="false"
      :url="customerUrl"
      :form-config-url="customerConfigUrl"
      @cancel="onHideCustomerForm"
      @saved="onCustomerSaved"
      :layout="FormModalLayout"
    />
    <ProjectFormComponent
      v-if="showProjectForm"
      :edit="false"
      :url="projectUrl"
      :form-config-url="projectConfigUrl"
      @cancel="onHideProjectForm"
      @saved="onProjectSaved"
      :layout="FormModalLayout"
    />
  </div>
</template>
